#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <img.h>
#include <math.h>
#include <mouse.h>

#define CLICK_ON_M  -4
#define CLICK_ON_L  -3
#define CLICK_ON_UP -2
#define CLICK_ON_QUIT   -1
#define FILE 1
#define FOLDER 0
#define HIDDEN 4

#define TRUE 1
#define FALSE 0

#define ICON_W 24 + 24 * iconSize
#define ICON_H ICON_W + 20 * iconSize

typedef struct {
    int cantFiles;
    char ** files;
    int cantDirects;
    char ** directs;
} TFileContent;

typedef struct {
    imgT * backg;
    imgT * screen;
    imgT * folder;
    imgT * file;
    imgT * fileH;
    imgT * folderH;
    imgT * cursor;
    imgT * hand;
    imgT * buffer;
} TImages;

int iconSize = 0;
TFileContent fileContent;
TImages images;
char * pwd;
imgT * vec_images[8];
point_t position;

void drawPointer(int x, int y);
void erasePointer(int x, int y);
void drawFolder(int x, int y, char *name);
void drawFile(int x, int y, char *name);
void drawAll(void);
int whereClicked(int xClick, int yClick);
int clickOnButton(int xClick, int yClick);
int getFilesPerLine(void);
int getCantLines(void);
void setIconSize(void);
void listFiles(void);
void initFileContents(void);
void freeFileContent(void);
void upLevelPwd(void);
void enterFolder(int index);
void initImages(void);
void showPath(void);
void showBG(void);
void drawHand(int x, int y);

int whereClicked2(int xClick, int yClick);

int flag;

int
main(void)
{
	char input;
    int x, y, xold, yold, clickOn, flags, click, first;
    colorT color = {255,0,0};
    first = 1;
    flag = 1;

    initFileContents();
    initImages();
    create_mouse_pointer(images.screen->w, images.screen->h);

    get_mouse_pos(&position);
    xold=position.x;
    yold=position.y;

    pwd = calloc(1,100);
    listFiles();
	
	flags = fcntl(0, F_GETFL, 0);

	/*Pongo non block*/
	fcntl(0, F_SETFL, flags | O_NONBLOCK);
    
	while(flag) {
		
		if ( read(0, &input, 1) == 1 && (input == 'q' || input == 'Q') )
			break;

        drawAll();

        get_mouse_pos(&position);
        x=position.x;
        y=position.y;
        click = get_left_pressed();
        
        
         if( x!=xold || y!=yold || click || first) {
            rectT rect, rect2;
            pointT point, point2;
            if(clickOn = whereClicked2(x,y)) {
            first = 0;
                drawHand(x, y);
            } else { 
                drawPointer(x, y);
            }
            
            xold = x;
            yold = y;
            
            imgScreenRefresh(images.screen);
            
            point.x = 0;
            point.y = 0;
            rect.orig = point;
            rect.w = images.hand->w;
            rect.h = images.hand->h/2;
            point2.x = x;
            point2.y = y;
            rect2.orig = point2;
            rect2.w = images.hand->w;
            rect2.h = images.hand->h/2;
            /*Tapar la imagen con el fondo salvado*/
            imgBlt(images.buffer, rect, images.screen, rect2, BLT_CPY);
         }

        if(click) {
            /*clickOn = whereClicked(x,y);*/
            if(clickOn > 0) {
                enterFolder(clickOn);
                listFiles();
                showBG();
            } else if(clickOn == CLICK_ON_QUIT) {
                flag = 0;

            } else if(clickOn == CLICK_ON_UP) {
                upLevelPwd();
                listFiles();
                showBG();
            } else if(clickOn == CLICK_ON_M) {
                if(iconSize == 0) {
                    setIconSize();
                    showBG();
                }
            } else if(clickOn == CLICK_ON_L) {
                if(iconSize == 1) {
                    setIconSize();
                    showBG();
                }
            }
        }
    }

	                

    imgFree(vec_images[0]);
    imgFree(vec_images[1]);
    imgFree(vec_images[2]);
    imgFree(vec_images[3]);
    imgFree(vec_images[4]);
    imgFree(vec_images[5]);
    imgFree(vec_images[6]);
    imgFree(vec_images[7]);
    
    imgFree(images.backg);
    imgFree(images.cursor);
    imgFree(images.buffer);
    imgFree(images.screen);
    printf("libere\n");


	fcntl(0, F_SETFL, flags);
    free(pwd);
    return 0;
}

void initImages(void) {
    
    vec_images[0] = imgLoad("/usr/img/dirTransL.bmp", IMG_BMP);
    vec_images[1] = imgLoad("/usr/img/fileTransL.bmp", IMG_BMP);
    vec_images[2] = imgLoad("/usr/img/dirTrans.bmp", IMG_BMP);
    vec_images[3] = imgLoad("/usr/img/fileTrans.bmp", IMG_BMP);
    vec_images[4] = imgLoad("/usr/img/dirTranLH.bmp", IMG_BMP);
    vec_images[5] = imgLoad("/usr/img/fileTranLH.bmp", IMG_BMP);
    vec_images[6] = imgLoad("/usr/img/dirTransH.bmp", IMG_BMP);
    vec_images[7] = imgLoad("/usr/img/fileTransH.bmp", IMG_BMP);

    setIconSize();

    images.backg = imgLoad("/usr/img/backg.bmp", IMG_BMP);
    images.hand = imgLoad("/usr/img/hand.bmp", IMG_BMP);
    images.cursor = imgLoad("/usr/img/cursor2.bmp", IMG_BMP);
    images.buffer = imgCreate(images.hand->w, images.hand->h/2);

    images.screen = imgScreen(getResolutionCode(images.backg));

    showBG();
    /*imgScreenRefresh(images.screen);*/

}

void showBG(void){
    rectT frst;
    
    frst.w = images.screen->w;
    frst.h = images.screen->h;
    frst.orig.x = 0;
    frst.orig.y = 0;

    imgBlt(images.backg, frst, images.screen, frst, BLT_CPY);
}

void
drawHand(int x, int y) {
    pointT point, point2;
    rectT rect , rect2, mask;
    point.x = 0;
    point.y = 0;
    rect.orig = point;
    rect.w = images.hand->w;
    rect.h = images.hand->h/2;
    point2.x = x;
    point2.y = y;
    rect2.orig = point2;
    rect2.w = images.hand->w;
    rect2.h = images.hand->h/2;
    mask.w = images.hand->w;
    mask.h = images.hand->h/2;
    mask.orig.x = 0;
    mask.orig.y = images.hand->h/2;

    /*Salvar el fondo*/
    imgBlt(images.screen, rect2, images.buffer, rect, BLT_CPY);
    /*Bltear la mascara*/
    imgBlt(images.hand, mask, images.screen, rect2, BLT_AND);
    /*Bltear la imagen en si*/
    imgBlt(images.hand, rect, images.screen, rect2, BLT_OR);
}


/*
** Dibuja la flechita
*/
void
drawPointer(int x, int y) {

    pointT point, point2;
    rectT rect , rect2, mask;
    point.x = 0;
    point.y = 0;
    rect.orig = point;
    rect.w = images.cursor->w;
    rect.h = images.cursor->h/2;
    point2.x = x;
    point2.y = y;
    rect2.orig = point2;
    rect2.w = images.cursor->w;
    rect2.h = images.cursor->h/2;
    mask.w = images.cursor->w;
    mask.h = images.cursor->h/2;
    mask.orig.x = 0;
    mask.orig.y = images.cursor->h/2;

    /*Salvar el fondo*/
    imgBlt(images.screen, rect2, images.buffer, rect, BLT_CPY);
    /*Bltear la mascara*/
    imgBlt(images.cursor, mask, images.screen, rect2, BLT_AND);
    /*Bltear la imagen en si*/
    imgBlt(images.cursor, rect, images.screen, rect2, BLT_OR);

}

/*
** Borra la flechita
*/
void
erasePointer(int x, int y) {
    imgScreenRefresh(images.screen);
    /*DrawLine(x, y, x + 1, y + 6, BACKGROUND);
    DrawLine(x + 1, y + 6, x + 4, y + 4, BACKGROUND);
    DrawLine(x + 4, y + 4, x, y, BACKGROUND);*/
}

/*
** Dibuja el icono de una carpeta (temporamente un cuadrado)
*/
void
drawFolder(int x, int y, char *name) {
    pointT point, point2;
    char * path = NULL;
    rectT rect , rect2, mask;
    colorT color = {0xFF,0xFF,0xFF};
    point.x = 0;
    point.y = 0;
    rect.orig = point;
    rect.w = images.folder->w;
    rect.h = images.folder->h/2;
    point2.x = x;
    point2.y = y;
    rect2.orig = point2;
    rect2.w = images.screen->w;
    rect2.h = images.screen->h;
    mask.w = images.folder->w;
    mask.h = images.folder->h/2;
    mask.orig.x = 0;
    mask.orig.y = images.folder->h/2;
    path = realloc(path, strlen(pwd) + 2 + strlen(name));
    strcpy(path, pwd);
    strcpy(path + strlen(pwd), "/");
    strcpy(path + strlen(pwd) + 1, name);
    /*Bltear la mascara*/
    imgBlt(images.folder, mask, images.screen, rect2, BLT_AND);
    if(access(path,H_OK) != 0){
        /*Bltear la imagen en si*/
        imgBlt(images.folder, rect, images.screen, rect2, BLT_OR);
    } else {
        /*Bltear la imagen en si*/
        imgBlt(images.folderH, rect, images.screen, rect2, BLT_OR);
    }

    draw_boxed_string(images.screen, name, (int)(x + images.folder->w / 2.0 - \
    	 (4 * (iconSize + 1)) * ((strlen(name) < 8)? strlen(name) : 8)), y + \
    	  images.folder->h / 2, iconSize + 1, 8, 3, color);
          
     free(path);
}

/*
** Dibuja el icono de un archivo (temporalmente un cuadrado)
*/
void
drawFile(int x, int y, char *name) {
    pointT point, point2;
    rectT rect , rect2, mask;
    char * path = NULL;
    colorT color = {0xFF,0xFF,0xFF};
    point.x = 0;
    point.y = 0;
    rect.orig = point;
    rect.w = images.file->w;
    rect.h = images.file->h/2;
    point2.x = x;
    point2.y = y;
    rect2.orig = point2;
    rect2.w = images.screen->w;
    rect2.h = images.screen->h;
    mask.w = images.file->w;
    mask.h = images.file->h/2;
    mask.orig.x = 0;
    mask.orig.y = images.file->h/2;
    
    
    
    path = realloc(path, strlen(pwd) + 2 + strlen(name));
    strcpy(path, pwd);
    strcpy(path + strlen(pwd), "/");
    strcpy(path + strlen(pwd) + 1, name);
    /*Bltear la mascara*/
    imgBlt(images.file, mask, images.screen, rect2, BLT_AND);
    if(access(path,H_OK) != 0){
        /*Bltear la imagen en si*/
        imgBlt(images.file, rect, images.screen, rect2, BLT_OR);
    } else {
        /*Bltear la imagen en si*/
        imgBlt(images.fileH, rect, images.screen, rect2, BLT_OR);
    }

    draw_boxed_string(images.screen, name, (int)(x + images.file->w / 2.0 - \
    	(4 * (iconSize + 1)) * ((strlen(name) < 8)? strlen(name) : 8)), y + \
    	 images.folder->h / 2, iconSize + 1, 8, 3, color);
     free(path);
}

/*
** Dibuja todos los iconos en la pantalla
*/
void
drawAll(void) {
    int i, x, y, spaces;
    int cantLines = getCantLines();
    int filesPerLine = getFilesPerLine();
    spaces = (images.screen->w - images.file->w * filesPerLine) / (filesPerLine + 1);

    showPath();

    y = images.screen->h / 8;
    x = spaces;
    for( i = 0; i < fileContent.cantDirects + fileContent.cantFiles; i++) {
        if( i % filesPerLine == 0 && i != 0 ) {
            y += images.file->h;
            x = spaces;
        }
        if(i < fileContent.cantDirects) {
            drawFolder(x, y, fileContent.directs[i]);
            x += spaces + images.folder->w;
        } else {
            drawFile(x, y, fileContent.files[i-fileContent.cantDirects]);
            x += spaces + images.file->w;
        }
    }
}

/*
** Retorna el numero del icono sobre el que se hizo click (en funcion 
** de la posicion en la pantalla) o 0 si se clickeo sobre el fondo.
** Hay que mejorarla agregando lo de los botones.
*/
int
whereClicked(int xClick, int yClick) {
    int i, x, y, spaces;
    int buttonClicked = clickOnButton(xClick, yClick);
    int cantLines = getCantLines();
    int filesPerLine = getFilesPerLine();
    spaces = (images.screen->w - images.file->w * filesPerLine) / (filesPerLine + 1);
    y = images.screen->h / 8;
    x = spaces;
    
    if(buttonClicked != 0) {
        return buttonClicked;
    }

    for(i = 0; i < fileContent.cantDirects /*+ fileContent.cantFiles*/; i++) {
        if( i % filesPerLine == 0 && i != 0 ) {
            y += images.file->h;
            x = spaces;
        }
        if( xClick > x && xClick < x + ICON_W ) {
            if( yClick > y && yClick < y + ICON_H ) {
                return i + 1;
            }
        }
        x += spaces + images.file->w;
    }

    return 0;
}

int
whereClicked2(int xClick, int yClick) {
    int i, x, y, spaces;
    int fila, columna, x0, y0, icono;
    int buttonClicked = clickOnButton(xClick, yClick);
    int cantLines = getCantLines();
    int filesPerLine = getFilesPerLine();
    spaces = (images.screen->w - images.file->w * filesPerLine) / (filesPerLine + 1);
    y = images.screen->h / 8;
    x = spaces;
    
    if(buttonClicked != 0) {
	return buttonClicked;
    }
    
    x0 = xClick % (spaces + ICON_W);
    if(x0 < spaces) {
	return 0;
    }
    columna = xClick / (spaces + ICON_W) + 1;
    
    y0 = (yClick - y + images.file->h) % (ICON_H + images.file->h);
    if(y0 < images.file->h) {
	return 0;
    }
    fila = (yClick - y + images.file->h) / (ICON_H + images.file->h) + 1;
    
    icono = (fila -1) * filesPerLine + columna;
    if(icono <= fileContent.cantDirects) {
	return icono;
    }
    return 0;
}
    

int
clickOnButton(int xClick, int yClick) {
    colorT c = {255,0,0};
    if(yClick < 33 && yClick > 9) {
        if(xClick < 40 && xClick > 15 ) {
            return CLICK_ON_QUIT;
        } else if(xClick > 105 && xClick < 128 ) {
            return CLICK_ON_UP;
        } else if(xClick > 840 && xClick < 862 ) {
            return CLICK_ON_L;
        } else if(xClick > 916 && xClick < 937 ) {
            return CLICK_ON_M;
        }
    }
    
    return 0;
}

int
getFilesPerLine(void) {
    return (images.screen->w - 2 * images.file->w) / (images.file->w * 3);
}

int
getCantLines(void) {
    int val1;
    double val2;
    int filesPerLine = getFilesPerLine();
    val1 = (fileContent.cantDirects + fileContent.cantFiles) / filesPerLine;
    val2 = (double)(fileContent.cantDirects + fileContent.cantFiles) / filesPerLine;

    if(val2 - (double)val1 > -0.01 && val2 - (double)val1 < 0.01) {
        return val1;
    } else {
        return val1 + 1;
    }
}

void
setIconSize(void) {
    iconSize = 1 - iconSize;
    images.file = vec_images[2*(iconSize)+FILE];
    images.folder = vec_images[2*(iconSize)+FOLDER];
    images.fileH = vec_images[2*(iconSize)+FILE+HIDDEN];
    images.folderH = vec_images[2*(iconSize)+FOLDER+HIDDEN];
}

void
listFiles(void) {
    DIR * direct;
    struct dirent *opdir;
    struct stat attributes;
    char * path = NULL;
    getcwd(pwd, 100);
    direct = opendir(pwd);
    freeFileContent();
    fileContent.cantFiles = 0;
    fileContent.cantDirects = 0;
    fileContent.files = NULL;
    fileContent.directs = NULL;
    while((opdir = readdir(direct)) != NULL) {
        path = realloc(path, strlen(pwd) + 2 + strlen(opdir->d_name));
        strcpy(path, pwd);
        strcpy(path + strlen(pwd), "/");
        strcpy(path + strlen(pwd) + 1, opdir->d_name);
        stat(path, &attributes);
        if(S_ISDIR(attributes.st_mode)) {
            if(strcmp(opdir->d_name,".") != 0 && strcmp(opdir->d_name,"..") != 0) {
                if(fileContent.cantDirects % 10 == 0) {
                    fileContent.directs = realloc(fileContent.directs, (fileContent.cantDirects + 10) * sizeof(char*));
                }
                fileContent.directs[fileContent.cantDirects] = malloc(strlen(opdir->d_name) + 1);
                if (fileContent.directs[fileContent.cantDirects] == NULL) {
                	printf("malloc dio null");
                	flag = FALSE;
                	continue;
                }
                strcpy(fileContent.directs[fileContent.cantDirects], opdir->d_name);
                fileContent.cantDirects++;
            }
        } else {
            if(fileContent.cantFiles % 10 == 0) {
                fileContent.files = realloc(fileContent.files, (fileContent.cantFiles + 10) * sizeof(char*));
            }
            fileContent.files[fileContent.cantFiles] = malloc(strlen(opdir->d_name) + 1);
            if (fileContent.files[fileContent.cantFiles] == NULL) {
            	printf("malloc dio null");
            	flag = FALSE;
            	continue;
            }
            strcpy(fileContent.files[fileContent.cantFiles], opdir->d_name);
            fileContent.cantFiles++;
        }
    }
    closedir(direct);
    free(path);
}

void
freeFileContent(void) {
    int i;
    for(i = 0; i < fileContent.cantFiles; i++) {
        free(fileContent.files[i]);
    }
    for(i = 0; i < fileContent.cantDirects; i++) {
        free(fileContent.directs[i]);
    }
    if(fileContent.files) {
        free(fileContent.files);
    }
    if(fileContent.directs) {
        free(fileContent.directs);
    }
}

void
upLevelPwd(void) {
    chdir("..");
}

void
enterFolder(int index) {
    chdir(fileContent.directs[index - 1]);
}

void
initFileContents(void) {
    fileContent.files = NULL;
    fileContent.directs = NULL;
    fileContent.cantDirects = 0;
    fileContent.cantFiles = 0;
}

void
showPath(void) {
    char * show = NULL;
    colorT color = {0,0,0};
    int size = strlen(pwd);
    show = pwd;
    if(size > 55) {
        while(show[size] != '/') {
            size--;
        }
        show = pwd + strlen(pwd) - size + 2;
    }
    draw_string(images.screen, show, 240, 19, 1, color);
}

